<template>
<div class="crud-table-container">
  <div v-if="searchForm.length !== 0" class="crud-table-form">
    <a-form
      :model="formModel"
      :auto-label-width="true">
      <a-row :gutter="[20,10]">
        <a-col v-for="(item,index) in searchForm" 
        :span="item.span" 
        :xs="24"
        :sm="item.span*2"
        :md="item.span*2"
        :lg="item.span*1.2"
        :xl="item.span"
        :xxl="item.span"
        :key="index">
          <a-form-item :field="item?.field" :hide-label="item?.title == null || item?.title == '' ? true : false "
          :label="item?.title" label-col-flex="auto">
              <slot :name="item?.slots?.default" 
              v-bind="{ data: formModel, defaultValue: item?.defaultValue  }"></slot>
          </a-form-item>
        </a-col>
        <a-col :flex="'86px'" style="text-align: right">
          <a-space :size="18">
            <a-button type="primary" @click="onSearch">
                {{ searchBtnText }}
            </a-button>
            <a-button v-if="showResetBtn" @click="onReset">
              <template #icon><icon-refresh /></template>
              <span>重置</span>
            </a-button>
          </a-space>
        </a-col>
      </a-row>  
    </a-form>  
  </div>
  <div v-if="$slots.toolBtn"
  class="tool-btn-container">
    <slot name="toolBtn"></slot>
  </div>
  <a-table
    v-bind="$attrs"
    :bordered="{
      cell:bordered
    }"
    :data="tableData"
    :loading="loading"
    :columns="columns"
    column-resizable
    :pagination="showPage ? {
        size:'small',
        showTotal: false,
        showJumper: false,
        showPageSize: false,
        total: tableTotal,
        pageSize: pageSizeInit,
    }: false"
    page-position="bottom"
    @row-click="tableRowClick"
    @page-change="pageChange"
    @page-size-change="pageSizeChange">
      <template v-for="slotName in columnSlot" #[slotName]="{ record }">
        <slot :name="slotName" v-bind="{ record }"></slot>
      </template>
  </a-table>  
</div> 
</template>

<script lang="ts" setup>
import useLoading from '@/hooks/loading';
import { PropType } from 'vue';
import { TableColumnData } from '@arco-design/web-vue/es/table'
import { ref , reactive, computed, onMounted , watch} from 'vue'
import { isUndefined, isNull, isObject } from '@/utils/is'
import { PaginationProps } from '@arco-design/web-vue';


interface SearchFormProps {
  field: string, 
  title?: string, 
  span: number, 
  slots: any,
  defaultValue?: any
}


const {
  columns,
  fetchData,
  pageSize,
  searchForm,
  showPage
} = defineProps({
  columns: {
    type: Array as PropType<TableColumnData[]>,
    default: () => []
  },
  bordered: {
    type: Boolean,
    default: ()=> false
  },
  showPage: {
    type: Boolean,
    default: ()=> true
  },
  searchForm:{
    type: Array as PropType<SearchFormProps[]>,
    default: () => []
  },
  searchBtnText:{
    type: String,
    default: () => '筛选'
  },
  showResetBtn:{
    type: Boolean,
    default: false
  },
  pagination: {
    type: Boolean,
    default: true
  },
  pageSize:{
    type: Number,
    default: () => 20
  },
  fetchData:{
    type: Function,
    default: () => null
  }
});

let tableTotal = ref(0);
let tableData = ref([])
let pageInit = ref(1)
let pageSizeInit = ref(pageSize)

const emit = defineEmits([ 'rowClick' ])
interface ResultEntity {
   data: any[],
   total: number
}


let formModel = reactive({});
watch(()=> searchForm,(valList)=>{
  let fieldOj = {};
  valList.filter(item => isObject(item))
   .filter(item=> !isNull(item?.field) 
   && !isUndefined(item?.field) && item?.field !== '')
   .forEach(item=> {
    if(item?.field.replace(/\s/g, '') !== ''){
      let value = item?.field.replace(/\s/g, '');
      fieldOj[value] = item?.defaultValue == null 
      || item?.defaultValue == '' ? undefined : item?.defaultValue ;
    }
  });
  formModel = Object.assign(formModel, fieldOj);
},{
  deep:true,
  immediate:true,
})

const { loading, setLoading } = useLoading(true);
const columnSlot  = computed(()=> {
  let listSlot = []
  columns.filter(item => isObject(item))
  .filter(item =>!isNull(item?.slotName) 
  && !isUndefined(item?.slotName) 
  && item?.slotName !== '').forEach(item=> {
    if(item?.slotName.replace(/\s/g, '') !== ''){
      let value = item?.slotName.replace(/\s/g, '');
      if(listSlot.indexOf(value) == -1){ listSlot.push(value) }
    }
  })
  return listSlot as any[];
})



const onSearch = ()=>{
  tableFetchData(pageInit.value, pageSizeInit.value);
}

const onReset = ()=>{
  tableFetchData(1, pageSizeInit.value);
}

const pageChange = (page)=>{
  pageInit.value = page
  tableFetchData(page, pageSizeInit.value);
}

const pageSizeChange = (pageSize)=>{
  pageSizeInit.value = pageSize
  tableFetchData(pageInit.value, pageSize);
}

const tableFetchData = (page: number, size: number) : void =>{
    Promise.resolve((fetchData)({ query: formModel, page,size }))
    .then(({ data, total } : ResultEntity) => {
      tableData.value = data;
      tableTotal.value = total
      setLoading(false);
    }).catch((rest) => {
      tableData.value = [];
      tableTotal.value = 0
      setLoading(false);
    }).finally(()=>{
      setLoading(false);
    })
}

const tableRowClick = (data: any , event: any)=>{
    emit('rowClick', data , event)
} 

const reloadEvent = ()=>{
  tableFetchData(pageInit.value, pageSizeInit.value);
}

const queryEvent = ()=>{
  tableFetchData(pageInit.value, pageSizeInit.value);
}


onMounted(()=>{
  tableFetchData(pageInit.value, pageSizeInit.value);
})



defineExpose({ 
  reloadEvent,
  queryEvent 
});


</script>

<style scoped lang='less'>
 .crud-table-container{
  
 }

 :deep(.arco-table-container){
  .arco-table-th {
    background-color: #F5F5F5;
  }
  .arco-table-th-title{
    color: #333333 !important;
    font-weight: bold;
  }
 }

 :deep(.arco-pagination-list){
  .arco-pagination-item-active, 
  .arco-pagination-item-active:hover {
    color: #ffffff;
    background-color: #409EFF;
    border-color: transparent;
  }
 }

 .crud-table-form{
   margin: 21px 0px 16px 0px;
 }
 
 .tool-btn-container{
   margin: 0px 0px 16px 0px;
 }

 .arco-form-item {
    margin-bottom: 0px;
 }

</style>